﻿using System.Diagnostics;
using System.Runtime.CompilerServices;
using Internal.KuiHuaBaoDian.Services.Asset;
using UnityEngine;

namespace KuiHuaBaoDian.Services.Asset {

    public static class GameObjectExtension {

        /// <summary>
        /// 释放 GameObject 资产
        /// </summary>
        /// <param name="gameObject">要释放的 GameObject 实例</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Release(this GameObject gameObject) => UIOC.Application.Services.Get<IAssetService>().Release(gameObject);
    }

    [DebuggerStepThrough]
    [DebuggerNonUserCode]
    /// <summary>
    /// 资产句柄
    /// </summary>
    public readonly struct AssetHandle {

        /// <summary>
        /// 空值
        /// </summary>
        public static readonly AssetHandle None = new();

        /// <summary>
        /// GUID
        /// </summary>
        public System.Guid GUID { get; init; }

        public override readonly string ToString() => $"[({nameof(AssetHandle)}){GUID}]";

        public override readonly int GetHashCode() => GUID.GetHashCode();

        public override readonly bool Equals(object obj) {
            if (obj is AssetHandle other) {
                return other.GUID == GUID;
            }
            return false;
        }

        /// <summary>
        /// 转换为指定类型的资产句柄
        /// </summary>
        /// <typeparam name="T">资产类型</typeparam>
        /// <returns>转换后的句柄</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public AssetHandle<T> Convert<T>() where T : UnityEngine.Object => new() { GUID = GUID };

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsNone() => GUID == System.Guid.Empty;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsNotNone() => GUID != System.Guid.Empty;
    }

    /// <summary>
    /// 泛型资产句柄
    /// </summary>
    /// <typeparam name="T">资产类型</typeparam>
    public readonly struct AssetHandle<T> : System.IEquatable<AssetHandle<T>>, System.IEquatable<AssetHandle> where T : UnityEngine.Object {

        /// <summary>
        /// GUID
        /// </summary>
        public System.Guid GUID { get; init; }

        /// <summary>
        /// 资产内容
        /// </summary>
        public T Content => (UIOC.Application.Services.Get<IAssetService>() as IAssetServiceInternal).GetValue(this);

        /// <summary>
        /// 是否有资产内容
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool HasContent() => GUID != System.Guid.Empty && Content != null;

        /// <summary>
        /// 释放资产
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Release() => UIOC.Application.Services.Get<IAssetService>().Release(this);

        public override readonly string ToString() => $"[{nameof(AssetHandle<T>)}({GUID})]";

        public override readonly int GetHashCode() => GUID.GetHashCode();

        public override readonly bool Equals(object obj) {
            if (obj is AssetHandle<T> otherT) {
                return Equals(otherT);
            } else if (obj is AssetHandle other) {
                return Equals(other);
            }
            return false;
        }

        public bool Equals(AssetHandle<T> other) {
            return other.GUID == GUID;
        }

        public bool Equals(AssetHandle other) {
            return other.GUID == GUID;
        }

        public static implicit operator AssetHandle(AssetHandle<T> @in) {
            return new AssetHandle { GUID = @in.GUID };
        }
        public static implicit operator AssetHandle<T>(AssetHandle @in) {
            return new AssetHandle<T> { GUID = @in.GUID };
        }

        public static bool operator ==(AssetHandle<T> left, AssetHandle<T> right) => left.Equals(right);
        public static bool operator !=(AssetHandle<T> left, AssetHandle<T> right) => !left.Equals(right);

        public static bool operator ==(AssetHandle<T> left, AssetHandle right) => left.Equals(right);
        public static bool operator !=(AssetHandle<T> left, AssetHandle right) => !left.Equals(right);

        public static bool operator ==(AssetHandle left, AssetHandle<T> right) => right.Equals(left);
        public static bool operator !=(AssetHandle left, AssetHandle<T> right) => !right.Equals(left);
    }
}
